route.ts 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. import { NextRequest, NextResponse } from "next/server";
  2. import { basename } from "node:path";
  3. import { readUploadBuffer, resolveUploadPath } from "@/lib/chat-store";
  4. function guessContentType(fileName: string) {
  5. const lower = fileName.toLowerCase();
  6. if (lower.endsWith(".png")) return "image/png";
  7. if (lower.endsWith(".jpg") || lower.endsWith(".jpeg")) return "image/jpeg";
  8. if (lower.endsWith(".gif")) return "image/gif";
  9. if (lower.endsWith(".webp")) return "image/webp";
  10. if (lower.endsWith(".svg")) return "image/svg+xml";
  11. if (lower.endsWith(".pdf")) return "application/pdf";
  12. if (lower.endsWith(".txt")) return "text/plain; charset=utf-8";
  13. if (lower.endsWith(".zip")) return "application/zip";
  14. if (lower.endsWith(".rar")) return "application/vnd.rar";
  15. if (lower.endsWith(".doc")) return "application/msword";
  16. if (lower.endsWith(".docx")) {
  17. return "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
  18. }
  19. if (lower.endsWith(".xls")) return "application/vnd.ms-excel";
  20. if (lower.endsWith(".xlsx")) {
  21. return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
  22. }
  23. return "application/octet-stream";
  24. }
  25. export async function GET(
  26. request: NextRequest,
  27. context: { params: Promise<{ storageKey: string }> }
  28. ) {
  29. const { storageKey } = await context.params;
  30. const safeStorageKey = basename(storageKey);
  31. try {
  32. const fileBuffer = await readUploadBuffer(safeStorageKey);
  33. const contentType = guessContentType(safeStorageKey);
  34. const download = request.nextUrl.searchParams.get("download") === "1";
  35. return new NextResponse(fileBuffer, {
  36. headers: {
  37. "Content-Type": contentType,
  38. "Content-Disposition": `${download ? "attachment" : "inline"}; filename="${encodeURIComponent(safeStorageKey)}"`,
  39. "Cache-Control": "private, max-age=31536000, immutable"
  40. }
  41. });
  42. } catch {
  43. return NextResponse.json({ error: "文件不存在" }, { status: 404 });
  44. }
  45. }